/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package polylifegame.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Random;

/**
 *
 * @author epulapp
 */
public class Environnement extends Observable implements Simulable, Serializable {
    
    //<editor-fold defaultstate="collapsed" desc="Variables de classe">
    //Tableau de cases
    private Case[][] tabCases;
    //dimension du tableau en X
    private Integer tailleX;
    //dimension du tableau en Y
    private Integer tailleY;
    //</editor-fold>  
    
    //<editor-fold defaultstate="collapsed" desc="Constructeurs">
    /**
     * Constructeur par défaut
     */
    public Environnement(){
        this.tabCases = null;
        this.tailleX = 0;
        this.tailleY = 0;
    }
    
    /**
     * Constructeur personnalisé
     * @param tailleX
     * @param tailleY 
     */
    public Environnement(Integer tailleX, Integer tailleY) {
        this.tailleX = tailleX;
        this.tailleY = tailleY;
        this.tabCases = new Case[tailleX][tailleY];
        
        //Initialisation du tableau de cases (cases vides)
        for(int i=0; i<this.tailleX; i++){
            for(int j=0; j<this.tailleY; j++){
                this.tabCases[i][j] = new Case(this, i, j, false, false);
            }
        }
    }
    //</editor-fold>
    
    //<editor-fold defaultstate="collapsed" desc="Méthodes de classe">
    
    /**
     * Retourne le nombre de voisines vivantes de la case passée en paramètre
     */
    public Integer getVoisines(Case caseCourante){
        
        //Liste des cases activées
        ArrayList<Case> listeVoisines = new ArrayList<Case>();
        
        //Parcours des cases voisines pour récupérer les voisines vivantes
        for (int i = caseCourante.getPosX() - 1; i < caseCourante.getPosX() + 2; i++) {
            for (int j = caseCourante.getPosY() - 1; j < caseCourante.getPosY() + 2; j++) {
                
                if (i >= 0 && i < this.tailleX && j >= 0 && j < this.tailleY) {
                    if (!(i == caseCourante.getPosX() && j == caseCourante.getPosY())) {
                        
                        //Si la case est activée on l'ajoute au tableau
                        if(this.tabCases[i][j].getEtatN()){
                            listeVoisines.add(this.tabCases[i][j]);
                        }
                    }
                }
            }
        }
        return listeVoisines.size();
    }
    
    /**
     * Génère une grille de case aléatoirement
     */
    public void generationAleatoire() {

        Random random = new Random();
        
        for (int i = 0; i < this.tailleX; i++) {
            for (int j = 0; j < this.tailleY; j++) {
                
                this.tabCases[i][j].setEtatN(random.nextBoolean());
            }
        }
        
        //Notification de la modification de l'environnement
        this.setChanged();
        this.notifyObservers(this.tabCases);

    }
   
    
     /**
     * Génère une grille de case aléatoirement
     */
    public void generationMotif(int numMotif) {
        int num =numMotif;
        for (int i = 0; i < this.tailleX; i++) {
            for (int j = 0; j < this.tailleY; j++) {
                if(num == numMotif)
                {   this.tabCases[i][j].setEtatN(true);
                    num = 0;
                }
                else {
                    
                    this.tabCases[i][j].setEtatN(false);
                }
                
                num++;
            }
        }
        
        //Notification de la modification de l'environnement
        this.setChanged();
        this.notifyObservers(this.tabCases);

    }
    
    /**
     * Réinitialiser l'environnement
     */
    public void reinitialiserEnvironnement(){
        for (int i = 0; i < this.tailleX; i++) {
            for (int j = 0; j < this.tailleY; j++) {
                this.tabCases[i][j].setEtatN(Boolean.FALSE);
            }
        }
        
        //Notification de la modification de l'environnement
        this.setChanged();
        this.notifyObservers(this.tabCases);
    }
    
    /**
     * Mise à jour de l'environnement courant
     * @param numThread : Correspond au numéro du thread (Cela permet de savoir l'indice de début et de fin pour le parcourt du tableau)
     * @param nbThread : Correspond au nombre de thread
     */
    @Override
    public void calculerGeneration(int numThread, int nbThread){
        int début = (this.tailleX/ nbThread) * numThread;
        int fin = début + (this.tailleX/ nbThread);
                  
        //System.out.println("Thread : " + numThread  + "    Début : " + début + "      Fin : " + fin); 
 
        //Premier parcours du tableau pour calculer l'etat N+1 des cases
        for(int i=début; i < fin; i++){
            for(int j=0; j< this.tailleY; j++){
                this.tabCases[i][j].calculN1();
            }
        }
        
    }
    
    @Override
    /*
     * Mise a jour de l'état N
     */
     public void miseAJourEtatN(){
            //Second parcours du tableau pour mettre à jour les case par leur nouvel état
            for(int i=0; i<this.tailleX; i++){
                for(int j=0; j<this.tailleY; j++){
                    this.tabCases[i][j].MAJetatN();
                }
            }
            
            //Notification de la modification de l'environnement
            this.setChanged();
            this.notifyObservers(this.tabCases);
    }
    
    
    
    @Override
    public String toString() {
        
        String affichage = "Affichage de l'environnement courant \n\n";   
        for(int i =0; i<this.getTailleX(); i++){
            for(int j=0; j<this.getTailleY(); j++){
                affichage += "[ " + this.tabCases[i][j].toString() + " ] ";
            }
            //Saut de ligne
            affichage += "\n";
        }
        return affichage;
    }
    
    
    //</editor-fold>
 
    //<editor-fold defaultstate="collapsed" desc="Getters et Setters">
    public Case[][] getTabCases() {
        return tabCases;
    }

    public void setTabCases(Case[][] tabCases) {
        this.tabCases = tabCases;
        //Notification de la modification de l'environnement
        this.setChanged();
        this.notifyObservers(this.tabCases);
    }

    public Integer getTailleX() {
        return tailleX;
    }

    public void setTailleX(Integer tailleX) {
        this.tailleX = tailleX;
    }

    public Integer getTailleY() {
        return tailleY;
    }

    public void setTailleY(Integer tailleY) {
        this.tailleY = tailleY;
    }
    //</editor-fold>
  
}
